import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import static java.lang.System.out;

// To Remove: all cases where a color starts a search at a board where the opponent is to move
// i.e. all tests for 'losing' & some random board tests
// these situations should never occur (a player only starts a search when it's her turn)

public class TestNegaMax extends TestCase {
    private static final Class thisClass = TestNegaMax.class;

    final int MAX = ComputerPlayer.WHITE_WIN;
    final int MIN = ComputerPlayer.WHITE_LOSS;

    public static void main(String[] args) {
        if (args.length >= 1 && args[0].equals("text")) {
            junit.textui.TestRunner.run(thisClass);
        } else {
            junit.swingui.TestRunner.run(thisClass);
        }
    }

    public static Test suite() {
        return new TestSuite(thisClass);
    }

    public void testWinning1() {

	// Case: white takes the last black & is crowned within one move
	Board board = Board.parseWdp(".... .b.. .w.. .... .... .... .... .... w");

	NegaMax p = new NegaMax(board.blackToMove,new EvalMaterialOnly(),1);
	int bestValue = p.search(board, 1);
	
	assertEquals(MAX, bestValue);
    }

    public void testWinning2() {

	// Case: white blocks the last black within one move
	Board board = Board.parseWdp(".... .... ...b .... ..ww .... .... .... w");

	NegaMax p = new NegaMax(board.blackToMove,new EvalMaterialOnlyNeg(),1);
	int bestValue = p.search(board, 1);
	
	assertEquals(MAX, bestValue);
    }

    public void testEvalCrown() {
	// Case: white is crowned within one move
	Board board = Board.parseWdp(".... .w.. .... .... .b.. .... .... .... w");

	NegaMax p = new NegaMax(board.blackToMove,new EvalMaterialOnlyNeg(),1);
	int bestValue = p.search(board, 1);
	
	assertEquals(Eval.KINGS, bestValue);
    }

    public void testEvalCapture() {
	// Case: starting with same number of players (eval==0)
	//       white captures one black within one move

	Board board = Board.parseWdp("...b .... .b.. ..w. .... .... .... .w.. w");

	NegaMax p = new NegaMax(board.blackToMove,new EvalMaterialOnlyNeg(),1);
	int bestValue = p.search(board, 1);
	
	assertEquals(Eval.MEN, bestValue);
    }

    public void test2stepCapture() {
    }

    
    public void testAgainstMinimax() {

	for (int depth = 1; depth < 6; depth++) {
	    //out.println("depth=" + depth);

            MiniMax blackMini = new MiniMax(true, new EvalMaterialOnly(), depth);
            NegaMax blackNeg = new NegaMax(true, new EvalMaterialOnlyNeg(), depth);
            MiniMax whiteMini = new MiniMax(false, new EvalMaterialOnly(), depth);
            NegaMax whiteNeg = new NegaMax(false, new EvalMaterialOnlyNeg(), depth);
	    int i;
            for (i = 0; i < 1000; i++) {
                Board board = RandomBoard.randPieces();
		boolean isEqual = true;
                assertTrue(board.isSane());

		if (board.blackToMove) {
		    //out.println("black to move");

		    Board blackMiniBoard = blackMini.findMove(board);
		    Board blackNegBoard = blackNeg.findMove(board);

                    int blackMiniValue = blackMini.search(board, depth);
                    int blackNegValue = -blackNeg.search(board, depth);
                    //              assertEquals(blackMiniValue, blackNegValue);  

		    if (blackMiniBoard != null && blackNegBoard != null) {
			isEqual = blackMiniBoard.equals(blackNegBoard);
			//      			assertEquals(true, isEqual);
		    }

		    if( !isEqual || (blackMiniValue != blackNegValue) ) {
			out.println("Black to move, this board caused conflict:");
			GameEngine.printBoard(board);
			out.println("At depth: " + depth);
			out.println("Mini-choice:");
			GameEngine.printBoard(blackMiniBoard);
			out.println("Mini-val: " + blackMiniValue);
			out.println("Neg-choice:");
			GameEngine.printBoard(blackNegBoard);
                        out.println("Neg-val: " + blackNegValue);
			return;
		    }

		} else {
		    //out.println("white to move");

		    Board whiteMiniBoard = whiteMini.findMove(board);
		    Board whiteNegBoard = whiteNeg.findMove(board);

                    int whiteMiniValue = whiteMini.search(board, depth);
                    int whiteNegValue = whiteNeg.search(board, depth);
                    //              assertEquals(whiteMiniValue, whiteNegValue);  

		    if (whiteMiniBoard != null && whiteNegBoard != null) {
			isEqual = whiteMiniBoard.equals(whiteNegBoard);
			//      			assertEquals(true, isEqual);
		    }

		    if(!isEqual || (whiteMiniValue != whiteNegValue) ) {
			out.println("White to move, this board caused conflict:");
			GameEngine.printBoard(board);
			out.println("At depth: " + depth);
			out.println("Mini-choice:");
			GameEngine.printBoard(whiteMiniBoard);
			out.println("Mini-val: " + whiteMiniValue);
			out.println("Neg-choice:");
			GameEngine.printBoard(whiteNegBoard);
			out.println("Neg-val: " + whiteNegValue);
			return;
		    }

		}
            }
	} 
    }   
}
